//-----------------------------------------------------------------------------
//   File:      periph.c
//   Contents:  Hooks required to implement USB peripheral function.
//
// $Archive: /USB/Target/Fw/lp/periph.c $
// $Date: 3/23/05 3:03p $
// $Revision: 3 $
//
//
//-----------------------------------------------------------------------------
// Copyright 2003, Cypress Semiconductor Corporation
//
// This software is owned by Cypress Semiconductor Corporation (Cypress) and is
// protected by United States copyright laws and international treaty provisions. Cypress
// hereby grants to Licensee a personal, non-exclusive, non-transferable license to copy,
// use, modify, create derivative works of, and compile the Cypress Source Code and
// derivative works for the sole purpose of creating custom software in support of Licensee
// product ("Licensee Product") to be used only in conjunction with a Cypress integrated
// circuit. Any reproduction, modification, translation, compilation, or representation of this
// software except as specified above is prohibited without the express written permission of
// Cypress.
//
// Disclaimer: Cypress makes no warranty of any kind, express or implied, with regard to
// this material, including, but not limited to, the implied warranties of merchantability and
// fitness for a particular purpose. Cypress reserves the right to make changes without
// further notice to the materials described herein. Cypress does not assume any liability
// arising out of the application or use of any product or circuit described herein. Cypress?
// products described herein are not authorized for use as components in life-support
// devices.
//
// This software is protected by and subject to worldwide patent coverage, including U.S.
// and foreign patents. Use may be limited by and subject to the Cypress Software License
// Agreement.
//-----------------------------------------------------------------------------
#pragma NOIV               // Do not generate interrupt vectors

#include "..\inc\fx2.h"
#include "..\inc\fx2regs.h"
#include "..\inc\fx2sdly.h"
#include "..\inc\i2c.h"
#include "..\inc\sw_i2c.h"
#include "..\inc\sw_spi.h"

extern BOOL   GotSUD;         // Received setup data flag
extern BOOL   Sleep;
extern BOOL   Rwuen;
extern BOOL   Selfpwr;

BYTE   Configuration;      // Current configuration
BYTE   AlternateSetting;   // Alternate settings

#define LED_GREEN_PIN	PA1
#define PWR_5V_CTRL		PA0

#define CMD_TYPE_RESET              0x00
#define CMD_TYPE_STATR_LS           0x81
#define CMD_TYPE_READ_DATA          0x82

#define PIN_RESET_SRAM_ADDRESS		PA3

unsigned char Timer2_Count;
unsigned char auto_out;
unsigned char Test_Count;

#define USB_5V_CTRL			0xC5

#define USB_I2C_Start		0xD5
#define USB_I2C_Stop		0xD6
#define USB_I2C_Write		0xD7
#define USB_I2C_Read		0xD8

#define USB_SPI_INIT		0xD9
#define USB_SPI_PLAY_1BYTE	0xDA

//-----------------------------------------------------------------------------
#define EEPROM_5V_CTRL_FLAG		0x55
#define EEPROM_5V_CTRL_ADDR		0xFFFF
//Turn on/off 5V when power on
void ctrl_ext_5V(void)
{
	BYTE value;

	at24c64_read_bytes_at(AT24C64_ADDR, EEPROM_5V_CTRL_ADDR, &value, 1);
	if(value == EEPROM_5V_CTRL_FLAG) {
		PWR_5V_CTRL = 1; //TURN ON
	} else {
		PWR_5V_CTRL = 0; //TURN OFF
	}

    OEA |= 0x01;
}

//-----------------------------------------------------------------------------
// Task Dispatcher hooks
//   The following hooks are called by the task dispatcher.
//-----------------------------------------------------------------------------

void TD_Init(void)             // Called once at startup
{
    CPUCS |= bmCLKSPD1;//CPU Clock: 48MHz

    //IFCONFIG - TRM: 15.5.2
    IFCONFIG = bm3048MHZ | bmIFCFG1 | bmIFCFG0;
    SYNCDELAY;

    REVCTL = 0x03;
    SYNCDELAY; 
  
	/*
	*	Endpoint 2, 4, 6 and 8 Configuration Registers
	*	bit7	Activate an Endpoint.
	*			> 0:Deactivate,  1:Activate an endpoint (default)
	*	bit6	DIR Sets Endpoint Direction.
	*			> 0:OUT,  1:IN
	*	bit[5:4]Defines the Endpoint Type. The TYPE bits apply to all of the large-endpoint configuration registers.
	*			> 00:Invalid,  01:Isochronous,  10:Bulk (default),  11:Interrupt
	*	bit3	Sets Size of Endpoint Buffer. Endpoints 4  and 8 can only be 512 bytes. Endpoints 2 and 6 areselectable.
	*			> 0:512 bytes, 1:1024 bytes 
	*	bit[1:0]BUF[1:0] Buffering Type/Amount.
	*			> 00:Quad,  01:Invalid,  10:Double,  11:Triple
	*/

    EP2CFG = bmBIT7 | bmBIT5;
    SYNCDELAY; 
    EP6CFG = bmBIT7 | bmBIT6 | bmBIT5;
    SYNCDELAY; 
    EP4CFG = 0x00;
    SYNCDELAY; 
    EP8CFG = 0x00;
    SYNCDELAY; 
 
	//Restore FIFOs to Default State - TRM: 15.5.4
    FIFORESET = 0x80; 
    SYNCDELAY; 
    FIFORESET = 0x82;
    SYNCDELAY; 
    FIFORESET = 0x84;
    SYNCDELAY; 
    FIFORESET = 0x86;
    SYNCDELAY; 
    FIFORESET = 0x88;
    SYNCDELAY; 
    FIFORESET = 0x00;
    SYNCDELAY;

	//TRM - 15.6.4
    EP2FIFOCFG = 0x00;
    SYNCDELAY;

    EP6FIFOCFG = bmBIT3;//AUTOIN
    SYNCDELAY;

	EP4FIFOCFG = 0x00;
    SYNCDELAY;
    EP8FIFOCFG = 0x00;

 
    PINFLAGSAB = 0xe0;//FLAGB : EP6 Full Flag
    SYNCDELAY;
    PINFLAGSCD = 0x08;//FLAGC : EP2 Empty Flag
    SYNCDELAY;
 
	//configures the PA7 pin as nSLCS, the slave FIFO chip select.
    PORTACFG = bmBIT6;
    SYNCDELAY; 

	//LED port set
    LED_GREEN_PIN = 0;
    OEA |= 0x02;
    PIN_RESET_SRAM_ADDRESS = 1;

	//Timer2 setting, 10mS
    TL2  = 0xC0;
	TH2  = 0x63;
	RCAP2L = 0xC0;
	RCAP2H = 0x63;
	T2CON  = 0x00;
	Timer2_Count = 0;
	Test_Count = 0;
	TR2 = 1;

	auto_out = 0;

	i2c_hw_init();
}

void TD_Poll(void)             // Called repeatedly while the device is idle
{
	if(! auto_out) {
		if( !( EP2468STAT & bmEP2EMPTY ) ) { // EP2EF=0 when FIFO NOT empty, host sent packet
		  OUTPKTEND = 0x02;  // SKIP=0, pass buffer on to master 
		}
	}
	if(TF2) {
		TF2 = 0;
		if(Timer2_Count++ > 45) {
			Timer2_Count = 0;
			LED_GREEN_PIN = ~LED_GREEN_PIN;
		}
	}
}

BOOL TD_Suspend(void)          // Called before the device goes into suspend mode
{
   return(TRUE);
}

BOOL TD_Resume(void)          // Called after the device resumes
{
   return(TRUE);
}

//-----------------------------------------------------------------------------
// Device Request hooks
//   The following hooks are called by the end point 0 device request parser.
//-----------------------------------------------------------------------------

BOOL DR_GetDescriptor(void)
{
   return(TRUE);
}

BOOL DR_SetConfiguration(void)   // Called when a Set Configuration command is received
{
   Configuration = SETUPDAT[2];
   return(TRUE);            // Handled by user code
}

BOOL DR_GetConfiguration(void)   // Called when a Get Configuration command is received
{
   EP0BUF[0] = Configuration;
   EP0BCH = 0;
   EP0BCL = 1;
   return(TRUE);            // Handled by user code
}

BOOL DR_SetInterface(void)       // Called when a Set Interface command is received
{
   AlternateSetting = SETUPDAT[2];
   return(TRUE);            // Handled by user code
}

BOOL DR_GetInterface(void)       // Called when a Set Interface command is received
{
   EP0BUF[0] = AlternateSetting;
   EP0BCH = 0;
   EP0BCL = 1;
   return(TRUE);            // Handled by user code
}

BOOL DR_GetStatus(void)
{
   return(TRUE);
}

BOOL DR_ClearFeature(void)
{
   return(TRUE);
}

BOOL DR_SetFeature(void)
{
   return(TRUE);
}

BOOL DR_VendorCmnd(void)
{
    BYTE num, i;

	switch(SETUPDAT[1]) {
// Start I2C Code
	case USB_I2C_Start:
		i2c_start();
		break;
	case USB_I2C_Stop:
		i2c_stop();
		break;
	case USB_I2C_Write:
		EP0BUF[0] = i2c_write(SETUPDAT[2]);
		EP0BCH = 0;
        EP0BCL = 1; // Arm endpoint with # 1 to transfer
		while(EP0CS & bmEPBUSY);
		break;
	case USB_I2C_Read:
		EP0BUF[0] = i2c_read(SETUPDAT[2]);
		EP0BCH = 0;
        EP0BCL = 1; // Arm endpoint with # 1 to transfer
		while(EP0CS & bmEPBUSY);
		break;
// End I2C Code

// Start SPI Code
	case USB_SPI_INIT:
		spi_init(SETUPDAT[2]);
		break;
	case USB_SPI_PLAY_1BYTE:
		EP0BUF[0] = spi_play_one_byte(SETUPDAT[2]);
		EP0BCH = 0;
        EP0BCL = 1; // Arm endpoint with # 1 to transfer
		while(EP0CS & bmEPBUSY);
		break;
// End SPI Code
	case 0xC0://Write port
		IOD = SETUPDAT[2];
		break;
	case 0xC1://Read port
		EP0BUF[0] = IOD;
		EP0BCH = 0;
        EP0BCL = 1; // Arm endpoint with # 1 to transfer
		while(EP0CS & bmEPBUSY);
		break;
	case 0xC2://Set output enable
		num = SETUPDAT[2];
		OED = num;
		if(num > 0) {
			if(num == 0xFF) {
				LED_GREEN_PIN = 0;
				TR2 = 0;
			} else {
				TR2 = 1;
			}
		} else {
			LED_GREEN_PIN = 1;
			TR2 = 0;
		}
		break;
	case USB_5V_CTRL:
		if(SETUPDAT[2] > 0) {
			PWR_5V_CTRL = 1;
			i = EEPROM_5V_CTRL_FLAG;
		} else {
			PWR_5V_CTRL = 0;
			i = ~EEPROM_5V_CTRL_FLAG;
		}
		num = ~i;

		at24c64_read_bytes_at(AT24C64_ADDR, EEPROM_5V_CTRL_ADDR, &num, 1);
		if(num != i) {
			at24c64_write_bytes_at(AT24C64_ADDR, EEPROM_5V_CTRL_ADDR, &i, 1);
		}
		break;
	case 0xB4:
		EP0BCH = 0;
        SYNCDELAY;
		num = SETUPDAT[6];
		EP0BCL = num;
		SYNCDELAY;
        while(EP0CS & bmEPBUSY);//Waiting for DATA Stage finish

		at24c64_write_bytes_at(AT24C64_ADDR, (WORD)SETUPDAT[2] | (((WORD)SETUPDAT[3])<<8), EP0BUF, num);
		TR2 = 0;
		LED_GREEN_PIN = ~LED_GREEN_PIN;
		break;
	case 0xB3:
		at24c64_read_bytes_at(AT24C64_ADDR, (WORD)SETUPDAT[2] | (((WORD)SETUPDAT[3])<<8), EP0BUF, SETUPDAT[6]);
		EP0BCH = 0;
		EP0BCL = SETUPDAT[6];
		TR2 = 1;
		break;
	case 0xB2:
        if( !auto_out ) {
			auto_out = 1;
			//EP2 switch to auto out
		    EP2FIFOCFG = bmBIT4;//AUTOOUT
		    SYNCDELAY;
		}
		//pull pin to tell fpga reset sram address
		PIN_RESET_SRAM_ADDRESS = 1;
		LED_GREEN_PIN = ~LED_GREEN_PIN;
		PIN_RESET_SRAM_ADDRESS = 0;
		break;
	case 0xB1:
		for(i=0; i<64; i++) {
           *(EP0BUF+i) = Test_Count++;
		}

        EP0BCH = 0;
        EP0BCL = 64; // Arm endpoint with # 64 to transfer
        while(EP0CS & bmEPBUSY);
		break;
	case 0xB0:
	    if ((SETUPDAT[6] != 0) && (!auto_out )) {
	        EP0BCH = SETUPDAT[7];
	        SYNCDELAY;
			num = SETUPDAT[6];
			EP0BCL = num;
			SYNCDELAY;
	        while(EP0CS & bmEPBUSY);//Waiting for DATA Stage finish
	
	        FIFORESET = 0x80;
	        SYNCDELAY;
	        FIFORESET = 0x02;
	        SYNCDELAY;
	        FIFORESET = 0x06;
	        SYNCDELAY;

	        for(i=0; i<num; i++) {
	            SYNCDELAY;
	            EP2FIFOBUF[i] = EP0BUF[i];
	        }

	        if(EP0BUF[0] == CMD_TYPE_RESET){
	            LED_GREEN_PIN = 0;
				TR2 = 1;
	        } else {
				if(EP0BUF[0] == CMD_TYPE_STATR_LS) {
					TR2 = 0;
		            LED_GREEN_PIN = 0;
		        } else if(EP0BUF[0] == CMD_TYPE_READ_DATA) {
		            TR2 = 1;
		        }
			}

	        SYNCDELAY;
	        EP2BCH = 0;
	        SYNCDELAY;
	        EP2BCL = num;
	        SYNCDELAY;
	        OUTPKTEND = 0x82; // skip uncommitted pkt. (second pkt.)
	        SYNCDELAY;

	        FIFORESET = 0x00;//restore normal operation.
			SYNCDELAY;
	    }
		break;
	default:
		break;
	}

	return(FALSE);
}

//-----------------------------------------------------------------------------
// USB Interrupt Handlers
//   The following functions are called by the USB interrupt jump table.
//-----------------------------------------------------------------------------

// Setup Data Available Interrupt Handler
void ISR_Sudav(void) interrupt 0
{
   GotSUD = TRUE;            // Set flag
   EZUSB_IRQ_CLEAR();
   USBIRQ = bmSUDAV;         // Clear SUDAV IRQ
}

// Setup Token Interrupt Handler
void ISR_Sutok(void) interrupt 0
{
   EZUSB_IRQ_CLEAR();
   USBIRQ = bmSUTOK;         // Clear SUTOK IRQ
}

void ISR_Sof(void) interrupt 0
{
   EZUSB_IRQ_CLEAR();
   USBIRQ = bmSOF;            // Clear SOF IRQ
}

void ISR_Ures(void) interrupt 0
{
   // whenever we get a USB reset, we should revert to full speed mode
   pConfigDscr = pFullSpeedConfigDscr;
   ((CONFIGDSCR xdata *) pConfigDscr)->type = CONFIG_DSCR;
   pOtherConfigDscr = pHighSpeedConfigDscr;
   ((CONFIGDSCR xdata *) pOtherConfigDscr)->type = OTHERSPEED_DSCR;
   
   EZUSB_IRQ_CLEAR();
   USBIRQ = bmURES;         // Clear URES IRQ
}

void ISR_Susp(void) interrupt 0
{
   Sleep = TRUE;
   EZUSB_IRQ_CLEAR();
   USBIRQ = bmSUSP;
}

void ISR_Highspeed(void) interrupt 0
{
   if (EZUSB_HIGHSPEED())
   {
      pConfigDscr = pHighSpeedConfigDscr;
      ((CONFIGDSCR xdata *) pConfigDscr)->type = CONFIG_DSCR;
      pOtherConfigDscr = pFullSpeedConfigDscr;
      ((CONFIGDSCR xdata *) pOtherConfigDscr)->type = OTHERSPEED_DSCR;
   }

   EZUSB_IRQ_CLEAR();
   USBIRQ = bmHSGRANT;
}
void ISR_Ep0ack(void) interrupt 0
{
}
void ISR_Stub(void) interrupt 0
{
}
void ISR_Ep0in(void) interrupt 0
{
}
void ISR_Ep0out(void) interrupt 0
{
}
void ISR_Ep1in(void) interrupt 0
{
}
void ISR_Ep1out(void) interrupt 0
{
}
void ISR_Ep2inout(void) interrupt 0
{
}
void ISR_Ep4inout(void) interrupt 0
{
}
void ISR_Ep6inout(void) interrupt 0
{
}
void ISR_Ep8inout(void) interrupt 0
{
}
void ISR_Ibn(void) interrupt 0
{
}
void ISR_Ep0pingnak(void) interrupt 0
{
}
void ISR_Ep1pingnak(void) interrupt 0
{
}
void ISR_Ep2pingnak(void) interrupt 0
{
}
void ISR_Ep4pingnak(void) interrupt 0
{
}
void ISR_Ep6pingnak(void) interrupt 0
{
}
void ISR_Ep8pingnak(void) interrupt 0
{
}
void ISR_Errorlimit(void) interrupt 0
{
}
void ISR_Ep2piderror(void) interrupt 0
{
}
void ISR_Ep4piderror(void) interrupt 0
{
}
void ISR_Ep6piderror(void) interrupt 0
{
}
void ISR_Ep8piderror(void) interrupt 0
{
}
void ISR_Ep2pflag(void) interrupt 0
{
}
void ISR_Ep4pflag(void) interrupt 0
{
}
void ISR_Ep6pflag(void) interrupt 0
{
}
void ISR_Ep8pflag(void) interrupt 0
{
}
void ISR_Ep2eflag(void) interrupt 0
{
}
void ISR_Ep4eflag(void) interrupt 0
{
}
void ISR_Ep6eflag(void) interrupt 0
{
}
void ISR_Ep8eflag(void) interrupt 0
{
}
void ISR_Ep2fflag(void) interrupt 0
{
}
void ISR_Ep4fflag(void) interrupt 0
{
}
void ISR_Ep6fflag(void) interrupt 0
{
}
void ISR_Ep8fflag(void) interrupt 0
{
}
void ISR_GpifComplete(void) interrupt 0
{
}
void ISR_GpifWaveform(void) interrupt 0
{
}

